package com.vinjogames.network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import com.vinjogames.util.Logger;

public class Server {
	public static String SERVER_IP;
	public static final int SERVER_PORT = 6969;

	public Handler handler = new Handler();
	private ConnectionManager mConnection;

	private ServerSocket serverSocket;
	public boolean running;

	private Thread mThread;

	public Server(ConnectionManager connection){
		mConnection = connection;
		running = false;
		SERVER_IP = getLocalIpAddress();
	}


	public class ServerThread implements Runnable {
		public void run() {
			try {
				if (SERVER_IP != null) {
					handler.post(new Runnable() {
						@Override
						public void run() {
							Logger.log("[Server] Listening on IP: " + SERVER_IP);
						}
					});
					serverSocket = new ServerSocket(SERVER_PORT);
					while (true) {
						running = true;
						// listen for incoming clients
						Socket client = serverSocket.accept();//Blocking call
						final String connectedClient = client.getInetAddress().toString();
						handler.post(new Runnable() {
							@Override
							public void run() {
								mConnection.setConnectedClientIP(connectedClient);
								Logger.log("[Server] " + connectedClient + " Connected.");
							}
						});
						try {
							BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
							String line = null;
							while ((line = in.readLine()) != null) {
								final String message = line;
								handler.post(new Runnable() {
									@Override
									public void run() {
										//mConnection.receive(message);
										Message msg = mConnection.getHandler().obtainMessage();
										msg.what = 1;
										Bundle b = new Bundle();
										b.putString("NetworkAction", message);
										msg.setData(b);
										mConnection.getHandler().sendMessage(msg);
									}
								});
							}
							break;
						} catch (Exception e) {
							handler.post(new Runnable() {
								@Override
								public void run() {
									Logger.log("[Server] Oops. Connection interrupted. Please reconnect your phones.");
								}
							});
							e.printStackTrace();
						}
					}
				} else {
					handler.post(new Runnable() {
						@Override
						public void run() {
							Logger.log("[Server] Couldn't detect internet connection.");
						}
					});
				}
			} catch (Exception e) {
				handler.post(new Runnable() {
					@Override
					public void run() {
						Logger.log("[Server] Error");
					}
				});
				e.printStackTrace();
			}
		}
	}

	private String getLocalIpAddress() {
		try {
			for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
				NetworkInterface intf = en.nextElement();
				for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
					InetAddress inetAddress = enumIpAddr.nextElement();
					if((inetAddress instanceof Inet4Address) && !inetAddress.isLoopbackAddress())
					{
						return inetAddress.getHostAddress().toString(); //TODO: need to test this
					}
					//if (!inetAddress.isLoopbackAddress()) { return inetAddress.getHostAddress().toString(); }
				}
			}
		} catch (SocketException ex) {
			Logger.log("[Server] Exception: " + ex.toString());
		}
		return null;
	}

	public String Start(){
		if(!running){
			mThread = new Thread(new ServerThread());
			mThread.start();
		}
		return SERVER_IP;
	}

	public void Stop() {
		if(running){
			running = false;
			try {
				if(serverSocket != null){
					serverSocket.close();
				}
				//destroyThread();
			} catch (IOException e) {
				Logger.log("[Server] Exception: " + e.getMessage());
			}
		}
	}

	//	private void destroyThread(){
	//		boolean retry = true;
	//		while (retry) {
	//			try {
	//				mThread.join();
	//				retry = false;
	//			} catch (InterruptedException e) {
	//				Logger.log("[Server] Exception: " + e.getMessage());
	//			}
	//		}
	//	}
}
